#include "pch.h"
#include "LogFile.h"
#include "LogManager.h"
#include "..\Common\SRWLock.h"

CLogFile::CLogFile(HMODULE hModule)
	: m_hModule(hModule)
	, m_hFile(INVALID_HANDLE_VALUE)
	, m_bInited(false)
	, m_nOldDate(0)
{
}

CLogFile::~CLogFile()
{
	FlushCache();

	if (m_hFile != INVALID_HANDLE_VALUE)
		CloseHandle(m_hFile);
}

void CLogFile::WriteLine(const std::string& strLine)
{
	if (m_bInited && m_hFile == INVALID_HANDLE_VALUE)
		return;

	SYSTEMTIME st;
	GetLocalTime(&st);
	int nCurDate = st.wYear * 10000 + st.wMonth * 100 + st.wDay;

	char szTime[64];
	int nTimeLen = sprintf_s(szTime, "[%02d:%02d:%02d.%03d] ", st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);

	CExclusiveLock lock(m_SRWLock);

	if (m_nOldDate != nCurDate)
	{
		m_nOldDate = nCurDate;

		// Output date first after date change
		char szDate[64];
		int nDateLen = sprintf_s(szDate, "============== %d-%02d-%02d ==============", st.wYear, st.wMonth, st.wDay);
		AppendData(szDate, nDateLen);
		AppendData("\r\n", 2);
	}

	AppendData(szTime, nTimeLen);
	AppendData(strLine.c_str(), strLine.size());
	AppendData("\r\n", 2);
}

void CLogFile::AppendData(LPCSTR lpData, size_t nSize)
{
	if (m_vecData.empty() || m_vecData.back().size() + nSize > 8000)
		m_vecData.emplace_back("").reserve(8000);

	m_vecData.back().append(lpData, nSize);
}

void CLogFile::FlushCache()
{
	CExclusiveLock lock(m_SRWLock);
	auto vecData = std::move(m_vecData);
	lock.Unlock();

	if (!m_bInited)
	{
		m_bInited = true;
		OpenFile();
	}

	if (m_hFile == INVALID_HANDLE_VALUE)
		return;

	for (const auto& strData : vecData)
	{
		DWORD dwWritten;
		WriteFile(m_hFile, strData.c_str(), (DWORD)strData.size(), &dwWritten, NULL);
	}
}

void CLogFile::OpenFile()
{
	wchar_t szFileName[MAX_PATH];
	if (!GetModuleFileNameW(m_hModule, szFileName, MAX_PATH))
	{
		assert(false);
		return;
	}

	// Get log file name
	wchar_t szLogFile[MAX_PATH];
	PathCombineW(szLogFile, CLogManager::GetLogPath(), PathFindFileNameW(szFileName));
	LPWSTR lpNameEnd = PathFindExtensionW(szLogFile);
	swprintf_s(lpNameEnd, MAX_PATH - (lpNameEnd - szLogFile), L"-%d.log", GetCurrentProcessId());

	for (int i = 0; i < 3; i++)
	{
		m_hFile = CreateFileW(szLogFile, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
		if (m_hFile != INVALID_HANDLE_VALUE)
			return;

		switch (GetLastError())
		{
		case ERROR_PATH_NOT_FOUND:
			CreateDirectoryW(CLogManager::GetLogPath(), NULL);
			break;

		case ERROR_ACCESS_DENIED:
			SetFileAttributesW(szLogFile, FILE_ATTRIBUTE_NORMAL);
			break;
		}
	}
}
